// SSCADA.cpp
#include "SSCADA.h"
#include <sstream>
#include <cmath>

SSCADA &SSCADA::getInstance()
{
    static SSCADA instance; // 静态局部变量
    return instance;
}

namespace
{
    // 获取当天的0点时间戳
    time_t getDayStart(time_t timestamp)
    {
        struct tm *tm = gmtime(&timestamp); // gmtime()函数将时间戳转换为UTC时间
        // 输出tm的年月日时分秒
        // std::cout << "tm: " << tm->tm_year + 1900 << "-" << tm->tm_mon + 1 << "-" << tm->tm_mday << " "
                //   << tm->tm_hour << ":" << tm->tm_min << ":" << tm->tm_sec << std::endl;
        tm->tm_hour = 0; // 将时分秒设置为0
        tm->tm_min = 0;
        tm->tm_sec = 0;
        // std::cout << "当天0点时间戳: " << timegm(tm) << std::endl;
        return timegm(tm); // timegm()函数将UTC时间转换为时间戳
    }
} // namespace的作用是限制函数的作用域，使得函数只能在当前文件中使用

int SSCADA::timeToIndex(time_t timestamp) const
{
    struct tm *tm = gmtime(&timestamp);
    return tm->tm_hour * 12 + tm->tm_min / 5; // 每5分钟一个时间点
}

time_t SSCADA::indexToTime(int index) const
{
    int hour = index / 12;
    int minute = (index % 12) * 5;
    struct tm tm = *gmtime(&baseTime);
    tm.tm_hour = hour;
    tm.tm_min = minute;
    tm.tm_sec = 0;
    return timegm(&tm);
}

void SSCADA::loadMeasurement(const std::string &filename)
{
    std::lock_guard<std::mutex> lock(mtx);
    std::ifstream file(filename);
    if (!file)
    {
        throw std::runtime_error("无法打开文件: " + filename);
    }

    measurements.clear();
    std::string line;

    // 跳过标题行
    std::getline(file, line);

    while (std::getline(file, line))
    {
        std::stringstream ss(line);
        std::string id;
        std::string ts_str;
        std::string value_str;

        std::getline(ss, id, ','); // 以逗号为分隔符，getline()函数读取一行数据
        std::getline(ss, ts_str, ',');
        std::getline(ss, value_str, ',');

        time_t timestamp = std::stol(ts_str); // 将字符串转换为long类型
        float value = std::stof(value_str);

        // 初始化基准时间
        if (baseTime == 0)
        {
            // std::cout << "初始化基准时间" << timestamp << std::endl;
            baseTime = getDayStart(timestamp);
            // 输出baseTIme的unix时间戳和时间
            std::cout << "当天基准时间: " << baseTime << " ("
                      << std::put_time(gmtime(&baseTime), "%Y-%m-%d %H:%M:%S") << ")\n";
        }

        int index = timeToIndex(timestamp);
        if (index < 0 || index >= 288)
        {
            continue; // 忽略无效时间点
        }

        measurements[id][index] = value;
    }
}
void SSCADA::printStatInfo() const
{
    printStatInfo(baseTime, baseTime + 86100); // 86400秒=24小时
}

void SSCADA::printStatInfo(time_t start, time_t end) const
{
    std::lock_guard<std::mutex> lock(mtx);
    const int start_idx = std::max(timeToIndex(start), 0);
    std::cout << "start_idx: " << start_idx << std::endl;
    const int end_idx = std::min(timeToIndex(end), 287);
    std::cout << "end_idx: " << end_idx << std::endl;
    for (const auto &[id, values] : measurements)
    {
        float sum = 0;
        float max_val = -INFINITY;
        float min_val = INFINITY; // 无穷大
        std::vector<int> max_indices;
        std::vector<int> min_indices;

        int count = 0;
        for (int i = start_idx; i <= end_idx; ++i)
        {
            float val = values[i];
            const float epsilon = 1e-6;
            // 如果 val 接近于 0 就跳过
            if (fabs(val) < epsilon)
            {
                continue;
            }
            if (!std::isnan(val))
            {
                sum += val;
                if (val > max_val)
                {
                    max_val = val;
                    max_indices.clear();
                    max_indices.push_back(i);
                }
                else if (fabs(val - max_val) < epsilon)
                {
                    max_indices.push_back(i);
                }
                if (val < min_val)
                {
                    min_val = val;
                    min_indices.clear();
                    min_indices.push_back(i);
                }
                else if (fabs(val - min_val) < epsilon)
                {
                    min_indices.push_back(i);
                }
                ++count;
            }
        }

        if (count == 0)
        {
            std::cout << "测点 " << id << " 无有效数据\n";
            continue;
        }

        std::cout << "测点 " << id << " 统计信息:\n"
                  << "  平均值: " << sum / count << "\n"
                  << "  最大值: " << max_val << " (出现次数: " << max_indices.size() << ")\n";
        for (int idx : max_indices)
        {
            time_t max_time = indexToTime(idx);
            std::cout << "    Unix时间戳: " << max_time << ", 时间: "
                      << std::put_time(gmtime(&max_time), "%Y-%m-%d %H:%M:%S") << "\n";
        }

        std::cout << "  最小值: " << min_val << " (出现次数: " << min_indices.size() << ")\n";
        for (int idx : min_indices)
        {
            time_t min_time = indexToTime(idx);
            std::cout << "    Unix时间戳: " << min_time << ", 时间: "
                      << std::put_time(gmtime(&min_time), "%Y-%m-%d %H:%M:%S") << "\n";
        }
    }
}
